#!/usr/bin/env python3.9
# -*- encoding: utf-8 -*-
"""
@文件        :aliyun.py
@说明        : 阿里云sdk接口调用
@时间        :2022/11/30 10:38:06
@作者        :Mars
@版本        :1.0
"""
import base64
import datetime
import hmac
import json
import time

import oss2
from alibabacloud_facebody20191230.client import Client as FacebodyClient
from alibabacloud_facebody20191230.models import (
    DetectFaceRequest, GenerateHumanAnimeStyleRequest,DetectPedestrianRequest,
    GenerateHumanSketchStyleRequest, RecognizeFaceRequest)
from alibabacloud_imageseg20191230.client import Client as ImagesegClient
from alibabacloud_imageseg20191230.models import (SegmentBodyRequest,
                                                  SegmentFaceRequest,
                                                  SegmentHeadRequest)
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient
from Tea.exceptions import TeaException

from mars.apps.systems.models import AliConfig
from mars.utils.exceptions.enums import StatusCodeEnum
from mars.utils.exceptions.exceptions import APIException


class Aliyun:

    # 用模型取出阿里云接口参数配置数据

    _ali_config = None #AliConfig.objects.first()

    def __init__(self):
        pass
    
    @staticmethod
    def get_ali_config():
        Aliyun._ali_config = AliConfig.objects.first()
        if not Aliyun._ali_config:
            raise APIException(StatusCodeEnum.NODATA_ERR)
        return Aliyun._ali_config

    @staticmethod
    def __client_config():
        """创建接口调用Client"""

        ali_config = Aliyun.get_ali_config()
        if not ali_config:
            # 如果没有配置阿里云AI参数，抛出异常
            raise APIException(StatusCodeEnum.ALI_NOCONFIG_ERR)

        # client配置
        config = open_api_models.Config(
            access_key_id=ali_config.accesskey_id,
            access_key_secret=ali_config.accesskey_secret,
            region_id=ali_config.region,
        )
        return config

    def __get_bucket():
        """获取bucket"""
        ali_config =  Aliyun.get_ali_config()
        auth = oss2.Auth(
            access_key_id=ali_config.accesskey_id,
            access_key_secret=ali_config.accesskey_secret,
        )
        bucket = oss2.Bucket(
            auth,
            endpoint=ali_config.endpoint,
            bucket_name=ali_config.bucket_name,
        )

        return bucket

    @staticmethod
    def get_preurl(method, object_name):
        ali_config =  Aliyun.get_ali_config()
        """上传或下载"""
        bucket = Aliyun.__get_bucket()

        return bucket.sign_url(
            method=(method or "GET"), key=object_name, expires=ali_config.expire_time, slash_safe=True
        )

    @staticmethod
    def __visioncaller(client: str, request: str, function: str, params: dict) -> dict:
        """动态调用API函数"""
        # 通过client名称创建客户端实例
        _client = globals()[client](Aliyun.__client_config())
        # 创建调用请求包含请求参数
        req = globals()[request](**params)
        runtime = util_models.RuntimeOptions()

        try:
            # 调用阿里云提供API功能
            resp = getattr(_client, function)(req, runtime)
            # 将返回值转为Json格式然后转为字典
            result = json.loads(UtilClient.to_jsonstring(resp))
            # 判断状态码是否正常
            if result["statusCode"] != 200:
                raise APIException(StatusCodeEnum.ALI_API_ERR)
            # 返回数据部分
            return result["body"]["Data"]
        except TeaException as error:
            print("err",error)
            # 抛出异常
            raise APIException(
                StatusCodeEnum.ALI_API_ERR, UtilClient.to_string(error.message)
            )

    @staticmethod
    def detect_face(image_url):
        """检测人脸信息"""
        return Aliyun.__visioncaller(
            client="FacebodyClient",
            request="DetectFaceRequest",
            function="detect_face_with_options",
            params={"image_url": image_url},
        )

    @staticmethod
    def detect_pedestrian(image_url):
        """检测人体位置"""
        return Aliyun.__visioncaller(
            client="FacebodyClient",
            request="DetectPedestrianRequest",
            function="detect_pedestrian_with_options",
            params={"image_url": image_url},
        )


    @staticmethod
    def segment_head(image_url):
        """分割图片中人物头像"""
        return Aliyun.__visioncaller(
            client="ImagesegClient",
            request="SegmentHeadRequest",
            function="segment_head_with_options",
            params={"image_url": image_url},
        )

    @staticmethod
    def segment_face(image_url):
        """面部分割"""
        return Aliyun.__visioncaller(
            client="ImagesegClient",
            request="SegmentFaceRequest",
            function="segment_face_with_options",
            params={"image_url": image_url},
        )

    @staticmethod
    def segment_body(image_url):
        """分割图片中人物整体"""
        return Aliyun.__visioncaller(
            client="ImagesegClient",
            request="SegmentBodyRequest",
            function="segment_body_with_options",
            params={"image_url": image_url},
        )

    @staticmethod
    def generate_human_anime_style(image_url, algo_type="anime"):
        """人物图片卡通化
        anime:日漫风  3d:3D特效   handdrawn:手绘风  sketch:铅笔画 artstyle:艺术特效
        """
        return Aliyun.__visioncaller(
            client="FacebodyClient",
            request="GenerateHumanAnimeStyleRequest",
            function="generate_human_anime_style_with_options",
            params={"image_url": image_url, "algo_type": algo_type},
        )

    @staticmethod
    def generate_human_sketch_style(image_url):
        """人体素描画"""
        return Aliyun.__visioncaller(
            client="FacebodyClient",
            request="GenerateHumanSketchStyleRequest",
            function="generate_human_sketch_style_with_options",
            params={"image_url": image_url},
        )

    @staticmethod
    def recognize_face(image_url, other_params={"age":True}):
        """人脸属性检测"""
        return Aliyun.__visioncaller(
            client="FacebodyClient",
            request="RecognizeFaceRequest",
            function="recognize_face_with_options",
            params={"image_url": image_url, **other_params},
        )

    def __get_iso_8601(expire):
        gmt = datetime.datetime.utcfromtimestamp(expire).isoformat()
        gmt += "Z"
        return gmt

    """上传签名"""

    @staticmethod
    def get_policy(object_name):
        ali_config =  Aliyun.get_ali_config()
        # 计算超时时间
        now = int(time.time())
        expire_syncpoint = now + ali_config.expire_time
        expire = Aliyun.__get_iso_8601(expire_syncpoint)
        policy_dict = {}
        policy_dict["expiration"] = expire

        # 计算signature
        condition_array = []
        array_item = []
        array_item.append("starts-with")
        array_item.append("$key")
        array_item.append(object_name)
        condition_array.append(array_item)
        policy_dict["conditions"] = condition_array
        policy = json.dumps(policy_dict).strip()
        policy_encode = base64.b64encode(policy.encode())
        h = hmac.new(
            ali_config.accesskey_secret.encode(),
            policy_encode,
            digestmod="sha1",
        )
        sign_result = base64.b64encode(h.digest()).strip()

        # 回调函数
        # callback_dict = {}
        # callback_dict['callbackUrl'] = AliyunClient.config.oss_callback_url
        # callback_dict['callbackBody'] = 'filename=${object}&size=${size}&mimeType=${mimeType}' \
        #                                 '&height=${imageInfo.height}&width=${imageInfo.width}'
        # callback_dict['callbackBodyType'] = 'application/x-www-form-urlencoded'
        # callback_param = json.dumps(callback_dict).strip()
        # base64_callback_body = base64.b64encode(callback_param.encode())

        # 组合签名数据
        token_dict = {}
        token_dict["accessid"] = ali_config.accesskey_id
        token_dict["host"] = (
            "https://"
            + ali_config.bucket_name
            + "."
            + ali_config.endpoint
        )
        token_dict["policy"] = policy_encode.decode()
        token_dict["signature"] = sign_result.decode()
        token_dict["expire"] = expire_syncpoint
        token_dict["dir"] = object_name
        # token_dict['callback'] = base64_callback_body.decode()

        return token_dict
